﻿using System.Text;
using System;

namespace SuperGo.SilverlightLib {
    public class Board {
        private readonly Intersection[,] _board;
		private static readonly int[,] STAR_POINTS_9 = new[,] { { 2, 2 }, { 6, 2 }, { 4, 4 }, { 2, 6 }, { 6, 6 } };
		private static readonly int[,] STAR_POINTS_13 = new[,] { { 3, 3 }, { 9, 3 }, { 6, 6 }, { 3, 9 }, { 9, 9 } };
		private static readonly int[,] STAR_POINTS_19 = new[,] { { 3, 3 }, { 9, 3 }, { 15, 3 }, { 3, 9 }, { 9, 9 }, { 15, 9 }, { 3, 15 }, { 9, 15 }, { 15, 15 } };

		private static readonly int[][,] HANDICAPS_9 = new int[9][,] { 
		    new int[,] { {2,6} },
		    new int[,] { {2,6}, {6,2} },
		    new int[,] { {2,6}, {6,2}, {2,2} },
		    new int[,] { {2,6}, {6,2}, {2,2}, {6,6} },
		    new int[,] { {2,6}, {6,2}, {2,2}, {6,6}, {4,4} },
		    new int[,] { {2,6}, {6,2}, {2,2}, {6,6}, {2,4}, {6,4} },
		    new int[,] { {2,6}, {6,2}, {2,2}, {6,6}, {4,4}, {2,4}, {6,4} },
		    new int[,] { {2,6}, {6,2}, {2,2}, {6,6}, {2,4}, {6,4}, {4,2}, {4,6} },
		    new int[,] { {2,6}, {6,2}, {2,2}, {6,6}, {2,4}, {6,4}, {4,2}, {4,6}, {4,4} },
		};

		private static readonly int[][,] HANDICAPS_13 = new int[9][,] { 
		    new int[,] { {3,9} },
		    new int[,] { {3,9}, {9,3} },
		    new int[,] { {3,9}, {9,3}, {3,3} },
		    new int[,] { {3,9}, {9,3}, {3,3}, {9,9} },
		    new int[,] { {3,9}, {9,3}, {3,3}, {9,9}, {6,6} },
		    new int[,] { {3,9}, {9,3}, {3,3}, {9,9}, {3,6}, {9,6} },
		    new int[,] { {3,9}, {9,3}, {3,3}, {9,9}, {6,6}, {3,6}, {9,6} },
		    new int[,] { {3,9}, {9,3}, {3,3}, {9,9}, {3,6}, {9,6}, {6,3}, {6,9} },
		    new int[,] { {3,9}, {9,3}, {3,3}, {9,9}, {3,6}, {9,6}, {6,3}, {6,9}, {6,6} },
		};

		private static readonly int[][,] HANDICAPS_19 = new int[9][,] { 
		    new int[,] { {3,15} },
		    new int[,] { {3,15}, {15,3} },
		    new int[,] { {3,15}, {15,3}, {3,3} },
		    new int[,] { {3,15}, {15,3}, {3,3}, {15,15} },
		    new int[,] { {3,15}, {15,3}, {3,3}, {15,15}, {9,9} },
		    new int[,] { {3,15}, {15,3}, {3,3}, {15,15}, {3,9}, {15,9} },
		    new int[,] { {3,15}, {15,3}, {3,3}, {15,15}, {9,9}, {3,9}, {15,9} },
		    new int[,] { {3,15}, {15,3}, {3,3}, {15,15}, {3,9}, {15,9}, {9,3}, {9,15} },
		    new int[,] { {3,15}, {15,3}, {3,3}, {15,15}, {3,9}, {15,9}, {9,3}, {9,15}, {9,9} },
		};

        public Board(int size) {
			_board = new Intersection[size, size];
            
			for (int y = 0; y < size; y++) {
                for (int x = 0; x < size; x++) {
                    _board[x, y] = new Intersection(x, y);
                }
            }
        }

		public Board Clone() {
            int size = Size;
			Board newBoard = new Board(size);
            for (int y = 0; y < size; y++) {
                for (int x = 0; x < size; x++) {
                    newBoard._board[x, y] = _board[x, y].Clone();
                }
            }
            return newBoard;
        }

		public int Size {
            get { return _board.GetLength(0); }
        }

        public Intersection this[int x, int y] {
            get { return _board[x, y]; }
            set { _board[x, y] = value; }
        }

        public bool IsStarPoint(int x, int y) {
            return IsStarPoint(Size, x, y);
        }

		public int[,] GetStarPoints() {
			return Board.GetStarPoints(Size);
		}

        public static int[,] GetStarPoints(int size) {
            if (size == 9)
                return STAR_POINTS_9;
            if (size == 13)
				return STAR_POINTS_13;
            else if (size == 19)
				return STAR_POINTS_19;
			throw new Exception("Star points are only supported for board sizes of 9, 13, and 19.");
        }

		public static int[,] GetHandicaps(int size, int handicaps) {
			if (handicaps < 2 || handicaps > 9)
				throw new Exception("Can't have fewer than 2 or more than 9 handicaps.");
			
			if (size == 9)
				return HANDICAPS_9[handicaps-1];
			if (size == 13)
				return HANDICAPS_13[handicaps-1];
			else if (size == 19)
				return HANDICAPS_19[handicaps-1];
			throw new Exception("Handicaps are only supported for board sizes of 9, 13, and 19.");
		}

        public static bool IsStarPoint(int size, int x, int y) {
            if (size == 9) {
                if (x == 2 && y == 2) return true;
                if (x == 6 && y == 2) return true;

                if (x == 4 && y == 4) return true;

                if (x == 2 && y == 6) return true;
                if (x == 6 && y == 6) return true;
            }
            else if (size == 13) {
                if (x == 3 && y == 3) return true;
                if (x == 9 && y == 3) return true;

                if (x == 6 && y == 6) return true;

                if (x == 3 && y == 9) return true;
                if (x == 9 && y == 9) return true;
            }
            else if (size == 19) {
                if (x == 3 && y == 3) return true;
                if (x == 9 && y == 3) return true;
                if (x == 15 && y == 3) return true;

                if (x == 3 && y == 9) return true;
                if (x == 9 && y == 9) return true;
                if (x == 15 && y == 9) return true;

                if (x == 3 && y == 15) return true;
                if (x == 9 && y == 15) return true;
                if (x == 15 && y == 15) return true;
            }
            return false;
        }

        public override bool Equals(object obj) {
            if (obj is Board) {
                Board board = (Board)obj;
                if (Size != board.Size) {
                    return false;
                }
                for (int y = 0; y < Size; y++) {
                    for (int x = 0; x < Size; x++) {
                        if (_board[x, y].State != board._board[x, y].State) {
                            return false;
                        }
                    }
                }
                return true;
            }
            return base.Equals(obj);
        }

        public override int GetHashCode() {
            return Size; // TODO: write an efficent hash routine.
        }

        public override string ToString() {
            StringBuilder sb = new StringBuilder();

            // write letters on top.
            sb.Append("   ");
            for (int x = 0; x < Size; x++) {
                sb.Append(_board[x, 0].Letter);
            }
            sb.AppendLine();

            // write board
            for (int y = 0; y < Size; y++) {
                sb.Append(string.Format("{0,2} ", y + 1));
                for (int x = 0; x < Size; x++) {
                    StoneState status = _board[x, y].State;
                    if (status == StoneState.White) {
                        sb.Append("O");
                    }
                    else if (status == StoneState.Black) {
                        sb.Append("X");
                    }
                    else {
                        sb.Append(".");
                    }
                }
                sb.AppendLine();
            }
            return sb.ToString();
        }
    }
}
